#include "ConstTest.h"
#include "TStatic.h"
#include "TInline.h"
#include "TConstructor.h"
#include "SB.h"

#include "TemplateDerived.h"
#include "iostream"


using namespace std;

void testConst()
{
  ConstTest test;
  cout << "test.m1():    ";
  test.m1();
  cout << "=============" << endl;

  cout << "static_cast<const ConstTest&>(test).m1():    ";
  static_cast<const ConstTest&>(test).m1();
  cout << "=============" << endl;

  const ConstTest constTest;
  cout << "constTest.m1():    ";
  constTest.m1();
  cout << "=============" << endl;
}

void testStatic()
{
  TStatic ts;
  TStatic ts1;
  cout << "ts.getSi():  " << ts.getSi() << endl;
  cout << "ts1.getSi(): " << ts1.getSi() << endl;

  ts.setSi(4);
  cout << "ts.getSi():  " << ts.getSi() << endl;
  cout << "ts1.getSi(): " << ts1.getSi() << endl;

}

/**
 * following code can be compiled but will throw throws exception when run
 */
void testRef()
{
  int* pi = NULL;
  int& ri = *pi;
  ri = 2;
}

void testRef2()
{
  int a[] = { 1, 2, 3, 4 };
  for( unsigned int index=0; index<sizeof(a)/sizeof(int); ++index )
  {
    int& v = *(a+index);
    cout << v << " ";
  }
}

/**
 * link error if inline method defined in the cpp file
 * undefined reference to `std::TInline::print()'
 */
void testInline()
{
  TInline tinline;
  tinline.print();
}

void testConstructor()
{
  {
    TConstructor cons1;
    cout << "default constructor: " << cons1.getName () << endl;
  }

  {
    //TConstructor cons2 ( "caller named." );  in fact will call the TConstructor(bool) and pointer is int and bool is int too
    TConstructor cons2 ( string( "caller named." ) );
    cout << "constructor with string parameter: " << cons2.getName () << endl;
  }
  {
    TConstructor cons3 (false);
    cout << "constructor with boolean parameter: " << cons3.getName () << endl;
  }
}


SB sb;

int f();  // forward declaration
int g();  // forward declaration

int x = f();
int y = g();

int f()
{
  std::cout << "using 'y' (which is " << y << ")\n";
  return 3*y + 7;
}

int g()
{
  std::cout << "initializing 'y'\n";
  return 5;
}

//SB theSb( SA sa )
//{
//  SB sb;
//  return sb;
//}

void testConstructorWrong()
{
  {
//    //the compile parses this as the declaring of the function which returns SB and take SA as parameter
//    SB theSb( SA() );
//    //compile error here: request for member 'm1' in 'theSb', which is of non-class type 'std::SB(std::SA (*)())'
//    theSb.m1();
  }

  {
    //this is ok
    SB theSb( (SA()) );
    theSb.m1();
  }
  {
    SB theSb = SB( SA() );
    theSb.m1();
  }

}

void testPrivateVirtual()
{
  TemplatePattern* temp = new TemplateDerived();
  temp->m();
}

int
main ()
{
  cout << "main () start..." << endl;

  //testConst();
  //testStatic();
  //testRef2();
  //testInline();
//  testConstructor();

//  cout << "before sb.m1()" << endl;
//  sb.m1();
//  cout << "after sb.m1()" << endl;

// test initialization sequence problem
//  cout << "======x, y======" << endl;
//  cout << "x=" << x << "; y=" << y << endl;
//
//  cout << "======f()======" << endl;
//  cout << f() << endl;

//  testConstructorWrong();

  testPrivateVirtual();
  return 0;
}
